package org.openharmony.qttool;

import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.util.io.FileUtil;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

import com.intellij.openapi.util.Key;

public class Utils {
    public static void handleException(Exception e) {
        e.printStackTrace();
        System.out.println(e.getMessage());
    }

    public static void copyDirectory(String src, String dest) {
        Path sourceDirectory = Paths.get(src);
        Path targetDirectory = Paths.get(dest);
        /*try {
            Files.walk(sourceDirectory)
                    .forEach(source -> {
                        Path target = targetDirectory.resolve(sourceDirectory.relativize(source));
                        try {
                            if (Files.isDirectory(source)) {
                                Files.createDirectories(target);
                            } else {
                                Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
                            }
                        } catch (IOException e) {
                            handleException(e);
                        }
                    });*/
        try (Stream<Path> walk = Files.walk(sourceDirectory)) {
            walk.forEach(source -> {
                Path target = targetDirectory.resolve(sourceDirectory.relativize(source));
                try {
                    if (Files.isDirectory(source)) {
                        Files.createDirectories(target);
                    } else {
                        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
                    }
                } catch (IOException e) {
                    handleException(e);
                }
            });
        } catch (IOException e) {
            handleException(e);
        }
    }

    public static void replaceFileContext(Path file, HashMap<String, String> replaceContext) {
        if (FileUtil.exists(file.toString())) {
            try {
                String newContext = Files.readString(file);
                for (Map.Entry<String, String> entry : replaceContext.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    newContext = newContext.replace(key, value);
                }
                // 写回文件
                try {
                    if (newContext == null) throw new RuntimeException("replace file context fail");
                } catch (RuntimeException e) {
                    handleException(e);
                }
                Files.write(file, newContext.getBytes());
            } catch (IOException e) {
                handleException(e);
            }
        }
    }

    public static String archOfBinary(String bin) {
        Path path = Paths.get(bin);
        try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path))) {
            byte[] buffer = new byte[1024];
            int bytesRead = bis.read(buffer, 0, buffer.length);
            if (bytesRead >= 20 &&
                    buffer[0] == 0x7f &&
                    buffer[1] == 'E' &&
                    buffer[2] == 'L' &&
                    buffer[3] == 'F') {
                for (int i = 0; i < 20; i++) {
                    boolean isLE = isLittleEndian(buffer, 5);
                    int machine = isLE ? getLEUint16(buffer, 18) : getBEUint16(buffer, 18);
//                    byte osAbi = getByte(buffer, 7);
                    switch (machine) {
                        case 3: // EM_386
                            return "x86";
                        case 8: // EM_MIPS
                            return "mips";
//                        case 20: // EM_PPC
//                            break;
//                        case 21: // EM_PPC64
//                            break;
                        case 40: // EM_ARM
                            return "armeabi-v7a";
                        case 183: // EM_AARCH64
                            return "arm64-v8a";
                        case 62: // EM_X86_64
                            return "x86_64";
//                        case 42: // EM_SH
//                            break;
//                        case 50: // EM_IA_64
//                            break;
                        default:
                            ;
                    }
                }
            }
        } catch (IOException e) {
            handleException(e);
        }
        return "unknown";
    }

    private static byte getByte(byte[] data, int pos) {
        return data[pos];
    }

    public static boolean isLittleEndian(byte[] data, int pos) {
        return getByte(data, pos) == 1;
    }

    private static void assertSize(byte[] byteArray, int size) {
        if (byteArray.length < size) {
            throw new IllegalArgumentException("Array size is less than the specified position.");
        }
    }

    public static int getLEUint16(byte[] byteArray, int pos) {
        assertSize(byteArray, pos + 1);
        int byte1 = byteArray[pos] & 0xFF;
        int byte2 = byteArray[pos + 1] & 0xFF;
        return (byte2 << 8) + byte1;
    }

    public static int getBEUint16(byte[] byteArray, int pos) {
        assertSize(byteArray, pos + 1);

        int byte1 = byteArray[pos] & 0xFF;
        int byte2 = byteArray[pos + 1] & 0xFF;

        return (byte1 << 8) + byte2;
    }

    private static final Key<QtSDK> qtkey = Key.create("Qt SDK");

    public static Key<QtSDK> qtSDKKey() {
        return qtkey;
    }

    public static String pluginPath() {
        PluginId pluginId = PluginId.getId("org.openharmony.qttool");
        IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(pluginId);
        try {
            if (plugin == null) {
                throw new RuntimeException("Plugin not found: " + pluginId);
            }
            Path path = plugin.getPluginPath();
            return path.toString();
        } catch (RuntimeException e) {
            handleException(e);
        }
        return "";
    }

    public static boolean readAndSaveToFile(Path read, Path save, HashMap<String, String> replaceContext) {
        if (FileUtil.exists(read.toString())) {
            try {
                String context = Files.readString(read);
                for (Map.Entry<String, String> entry : replaceContext.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    context = context.replace(key, value);
                }
                try {
                    if (context == null) throw new RuntimeException("read and save to file fail");
                } catch (RuntimeException e) {
                    handleException(e);
                }
                Files.write(save, context.getBytes(), StandardOpenOption.CREATE);
            } catch (IOException e) {
                handleException(e);
                return false;
            }
        }
        return true;
    }
}
